
#include "copyright.h"

#include "syscall.h"

int lock1, lock2;
int cond1, cond2;
int MV1, MV2;
char* choice;

void testWait(){
	Printing("T1: Attempting to acquire lock 1\n", ConsoleOutput, 0, 0);
	AcquireLock("lock1", 5);
	Printing("T1: Acquired lock 1. About to Wait\n", ConsoleOutput, 0, 0);
	Wait("condition1", 10, "lock1", 5);
	Printing("T1: Just woken up, about to release lock 1\n", ConsoleOutput, 0, 0);
	ReleaseLock("lock1", 5);
	Printing("T1: Released lock 1, about to exit\n", ConsoleOutput, 0, 0);
	Exit(0);
}

void testSignal(){
	Printing("T2: Attempting to acquire lock 1\n", ConsoleOutput, 0, 0);
	AcquireLock("lock1", 5);
	Printing("T2: Acquired lock 1. About to Signal\n", ConsoleOutput, 0, 0);
	Signal("condition1", 10, "lock1", 5);
	Printing("T2: Signaled T1, about to release lock 1\n", ConsoleOutput, 0, 0);
	ReleaseLock("lock1", 5);
	Printing("T2: Releasd lock 1, about to exit\n", ConsoleOutput, 0, 0);
	Exit(0);
}

void testWaitWithMonitor(){
	Printing("T1: Attempting to acquire lock 1\n", ConsoleOutput, 0, 0);
	AcquireLock("lock1", 5);
	Printing("T1: Acquired lock 1. About to Wait\n", ConsoleOutput, 0, 0);
	Wait("condition1", 10, "lock1", 5);
	Printing("T1: Just woken up, the monitor value is now %i\n", ConsoleOutput, GetMonitor("monitor1", 8, 0), 0);
	Printing("T1: About to Release lock 1\n", ConsoleOutput, 0, 0);
	ReleaseLock("lock1", 5);
	Printing("T1: Released lock 1, about to exit\n", ConsoleOutput, 0, 0);
	Exit(0);
}

void testSignalWithMonitor(){
	Printing("T2: Attempting to acquire lock 1\n", ConsoleOutput, 0, 0);
	AcquireLock("lock1", 5);
	Printing("T2: Acquired lock 1, about to set monitor value to 1\n", ConsoleOutput, 0, 0);
	SetMonitor("monitor1", 8, 1, 0);
	Printing("T2: Monitor value should be 1 now\n", ConsoleOutput, 0, 0);
	Signal("condition1", 10, "lock1", 5);
	Printing("T2: Signaled T1, about to release lock 1\n", ConsoleOutput, 0, 0);
	ReleaseLock("lock1", 5);
	Printing("T2: Releasd lock 1, about to exit\n", ConsoleOutput, 0, 0);
	Exit(0);
	
}

void serverTest1(){
	lock1 = -1;
	lock2 = -1;
	cond1 = -1;
	MV1 = -1;
	
	lock1 = CreateLock("lock1", 5);
	Printing("lock1 index = %i\n", ConsoleOutput, lock1, 0);
	if(lock1 == -1){
		Printing("Error when trying to create lock 1!\n", ConsoleOutput, 0, 0);
	}
	
	lock2 = CreateLock("lock2", 5);
	Printing("lock2 index = %i\n", ConsoleOutput, lock2, 0);
	if(lock2 == -1){
		Printing("Error when trying to create lock 2!\n", ConsoleOutput, 0, 0);
	}

	cond1 = CreateCondition("condition1", 10);
	Printing("cond1 index = %i\n", ConsoleOutput, cond1, 0);
	if(cond1 == -1){
		Printing("Error when trying to create cond 1!\n", ConsoleOutput, 0, 0);
	}

	MV1 = CreateMonitor("monitor1", 8);
	Printing("monitor1 index = %i\n", ConsoleOutput, MV1, 0);
	if(MV1 == -1){
		Printing("Error when trying to create MV 1!\n", ConsoleOutput, 0, 0);
	}

	Printing("Setting MV1 to 0.\n", ConsoleOutput, 0, 0);
	SetMonitor("monitor1", 8, 0, 0);
	
}

void serverTest2(){
	Printing("Testing Forking and Condition Wait and Signal\n", ConsoleOutput, 0, 0);
	
	Fork(testWait);
	Fork(testSignal);
}

void serverTest3(){
	Printing("Testing Forking, Condition Wait and Signal, and Monitor Variables\n", ConsoleOutput, 0, 0);
	
	Fork(testWaitWithMonitor);
	Fork(testSignalWithMonitor);
}

void doubleAcquire(){
	Printing("Trying to acquire lock 2\n", ConsoleOutput, 0, 0);
	AcquireLock("lock2", 5);
	Printing("Trying to acquire lock 2 again\n", ConsoleOutput, 0, 0);
	AcquireLock("lock2", 5);
	Printing("About to Release lock\n", ConsoleOutput, 0, 0);
	ReleaseLock("lock2", 5);
}

void menu(){
	serverTest1();
	
	Printing("Please choose one of the following options.\n", ConsoleOutput, 0, 0);
	
	Printing("1. Testing Condition Wait and Signal\n", ConsoleOutput, 0, 0);
	Printing("2. Testing Condition Wait and Signal with Monitor Variable Setting\n", ConsoleOutput, 0, 0);
	Printing("3. Trying to acquire the same lock twice, should show error on server side\n", ConsoleOutput, 0, 0);
	Printing("Note: only teh first digit you enter will be read (ie 456 will be read as 4)\n", ConsoleOutput, 0, 0);
	Read(choice, 1, ConsoleInput);
	
	
	if(*choice == '1'){
		serverTest2();
	} else if(*choice == '2'){
		serverTest3();
	} else if(*choice == '3'){
		doubleAcquire();
	}else {
		Printing("Invalid Input\n", ConsoleOutput, 0, 0);
	}
	return;
}

int main(){
	menu();
	Exit(0);
}